<template>
    <el-upload :accept="accept"
               :action="url() + (path ? '/' + path : '')"
               :auto-upload="autoUpload"
               :before-upload="beforeUpload"
               :file-list="fileList"
               :headers="getHeaders()"
               :limit="limit"
               :on-change="onChange"
               :on-error="onError"
               :on-exceed="onExceed"
               :on-remove="onRemove"
               :on-success="handleUploaded"
               :show-file-list="!autoUpload"
               multiple
               ref="uploader">
        <template v-if="!autoUpload">
            <el-button :size="size" :type="type">添加</el-button>
            <el-button :size="size" @click.stop="submit()" type="success">{{label}}</el-button>
        </template>
        <template v-else>
            <el-button :size="size" :type="type">{{label}}</el-button>
        </template>
    </el-upload>
</template>
<script lang="ts">
  import {BASE_URL} from '@/api/upload/uploadApi';
  import FileInfo from '@/structure/fileInfo';
  import Result from '@/structure/result';
  import UserUtil from '@/utils/user';
  import {ElUpload, ElUploadInternalFileDetail} from 'element-ui/types/upload';
  import {Component, Prop, Vue} from 'vue-property-decorator';

  interface IFile {
    name: string;
    url: string;
    uid: number;
  }

  @Component
  export default class UploadMultiple extends Vue {

    @Prop({
      default: ''
    })
    public path!: string;
    @Prop({
      default: null
    })
    public accept!: string;
    @Prop({
      default: null
    })
    public onSuccess!: (res: FileInfo[] | undefined) => void;
    @Prop({
      default: null
    })
    public onFail?: (error: { errorCode: number, message: string }) => void;
    @Prop({
      default: 'small'
    })
    public size!: string;
    @Prop({
      default: 'primary'
    })
    public type!: string;
    @Prop({
      default: '上传'
    })
    public label!: string;
    @Prop({
      default: true
    })
    public autoUpload!: boolean;
    @Prop({
      default: undefined
    })
    public limit!: number;
    @Prop()
    public beforeUpload!: (file: File) => (boolean | Promise<any>);

    public uploaded: 'PENDING' | 'FINISHED' | 'ERROR' = 'PENDING';
    public unUpload: number = 0;
    public fileInfos: { [key: number]: FileInfo } = {};
    public fileList: IFile[] = [];

    public onChange(file: ElUploadInternalFileDetail, fileList: ElUploadInternalFileDetail[]): void {
      this.unUpload = fileList.filter((item) => item.status !== 'success').length;
    }

    public handleUploaded({status, data, ...error}: Result<FileInfo>,
                          file: ElUploadInternalFileDetail, fileList: ElUploadInternalFileDetail[]): void {
      this.onChange(file, fileList);

      if (status) {
        this.fileInfos[file.uid] = data as FileInfo;

        if (this.unUpload > 0) {
          return;
        }

        this.uploaded = 'FINISHED';
        if (this.onSuccess && typeof this.onSuccess === 'function') {
          this.onSuccess(Object.values(this.fileInfos));
        }
      } else {
        this.uploaded = 'ERROR';
        if (this.onFail && typeof this.onFail === 'function') {
          this.onFail(error);
        }
      }
    }

    public submit(): Promise<void> {
      this.uploaded = 'PENDING';
      (this.$refs.uploader as ElUpload).submit();

      return new Promise<void>((resolve, reject) => {
        if (this.unUpload <= 0) {
          this.onSuccess(Object.values(this.fileInfos));
          resolve();
          return;
        }
        const checkUploadedStatus = () => {
          setTimeout(() => {
            if (this.uploaded === 'FINISHED') {
              this.onSuccess(Object.values(this.fileInfos));
              resolve();
            } else if (this.uploaded === 'ERROR') {
              reject();
            } else {
              checkUploadedStatus();
            }
          }, 1000 / 60);
        };
        checkUploadedStatus();
      });
    }

    public url(): string {
      return process.env.VUE_APP_API_URL + `/${BASE_URL}/single`;
    }

    public getHeaders(): { [key: string]: any } {
      const token = UserUtil.getAccessToken();
      return {
        Authorization: token ? token : '' as string
      };
    }

    public onExceed(): void {
      this.$message.warning(`最多可上传${this.limit} 个文件`);
    }

    public onError(err: ErrorEvent): void {
      this.uploaded = 'ERROR';
      if (this.onFail && typeof this.onFail === 'function') {
        this.onFail({
          errorCode: 0,
          message: err.message
        });
      }
    }

    public onRemove(file: ElUploadInternalFileDetail): void {
      if (file.status === 'success') {
        delete this.fileInfos[file.uid];
      }
    }

    public clearFiles(): void {
      (this.$refs.uploader as ElUpload).clearFiles();
      this.fileInfos = {};
      this.fileList.splice(0, this.fileList.length);
    }

    public setFileList(files: FileInfo[]): void {
      let list: FileInfo[] = [];
      list = list.concat(files);
      this.fileList.splice(0, this.fileList.length);
      this.fileInfos = {};
      for (let index = 0; index < list.length; index++) {
        const file = list[index];
        const item = {
          name: file.originalFilename,
          url: this.$getImageUrl(file.webPath),
          uid: Date.now() + index
        };
        this.fileInfos[item.uid] = file;
        this.fileList.push(item);
      }
    }
  }
</script>
<style scoped>
</style>
